﻿namespace EasyWeb.Test
{
    using System;
    using System.Data.Entity;
    using System.Linq;
    using System.Threading.Tasks;
    using EasyWeb.Data;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class EWSelectionItemDefinitionDao_Test : LibraryTest
    {
        public ew_tbl_selections Selection { get; private set; }

        [TestMethod]
        public async Task Select_Test()
        {
            var expecteds = new ew_tbl_selection_items[2];
            expecteds[0] = CreateRawSelectionItem("test1");
            expecteds[1] = CreateRawSelectionItem("test2");
            await this.TestDbContext.SaveChangesAsync();
            await this.TestDbContext.Entry(expecteds[0]).ReloadAsync();
            await this.TestDbContext.Entry(expecteds[1]).ReloadAsync();

            var actuals = await this.SelectionItemDefinitionDao.SelectAsync();
            Assert.AreEqual(2, actuals.Count());
            foreach (var actual in actuals)
            {
                var expected = expecteds.Single(e => e.ew_uid_selection_item_id == actual.Id);
                Assert.IsNotNull(expected);

                Assert.AreEqual(expected.ew_uid_selection_item_id, actual.Id);
                Assert.AreEqual(expected.ew_vc_key, actual.Key);
                Assert.AreEqual(expected.ew_xml_value, actual.Value.ToText());
                Assert.AreEqual(expected.ew_uid_selection_id, actual.SelectionDefinitionId);
                Assert.AreEqual(expected.ew_dt_created.ToUtc(), actual.Created);
                Assert.AreEqual(expected.ew_nvc_created_by, actual.CreatedBy);
                Assert.AreEqual(expected.ew_dt_modified.ToUtc(), actual.Modified);
                Assert.AreEqual(expected.ew_nvc_modified_by, actual.ModifiedBy);
                CollectionAssert.AreEqual(expected.ew_t_timestamp, actual.Timestamp);
            }
        }

        [TestMethod]
        public async Task Create_Test()
        {
            var text = new EWText();
            text.Values.Add(new EWTextValue("en", "v1"));
            text.Values.Add(new EWTextValue("zh-Hans", "v2"));
            var expected = new EWSelectionItemDefinition()
            {
                Key = "test",
                Value = text,
                SelectionDefinitionId = this.Selection.ew_uid_selection_id
            };
            await this.SelectionItemDefinitionDao.CreateAsync(expected);

            var actual = (await this.TestDbContext.ew_tbl_selection_items.ToArrayAsync()).ElementAt(0);
            Assert.AreEqual(expected.Id, actual.ew_uid_selection_item_id);
            Assert.AreEqual(expected.Key, actual.ew_vc_key);
            Assert.AreEqual(expected.Value.ToText(), actual.ew_xml_value);
            Assert.AreEqual(expected.SelectionDefinitionId, actual.ew_uid_selection_id);
            Assert.AreEqual(expected.Created, actual.ew_dt_created.ToUtc());
            Assert.AreEqual(expected.CreatedBy, actual.ew_nvc_created_by);
            Assert.AreEqual(expected.Modified, actual.ew_dt_modified.ToUtc());
            Assert.AreEqual(expected.ModifiedBy, actual.ew_nvc_modified_by);
            CollectionAssert.AreEqual(expected.Timestamp, actual.ew_t_timestamp);
        }

        [TestMethod]
        public async Task Update_Test()
        {
            var expected = CreateRawSelectionItem("test1");
            await this.TestDbContext.SaveChangesAsync();
            await this.TestDbContext.Entry(expected).ReloadAsync();

            var actual = new EWSelectionItemDefinition()
            {
                Id = expected.ew_uid_selection_item_id,
                Key = "test2",
                Value = expected.ew_xml_value.ToText(),
                SelectionDefinitionId = this.Selection.ew_uid_selection_id,
                Created = expected.ew_dt_created,
                CreatedBy = expected.ew_nvc_created_by,
                Modified = expected.ew_dt_modified,
                ModifiedBy = expected.ew_nvc_modified_by,
                Timestamp = expected.ew_t_timestamp
            };
            await this.SelectionItemDefinitionDao.UpdateAsync(actual);

            await this.TestDbContext.Entry(expected).ReloadAsync();

            Assert.AreEqual(expected.ew_uid_selection_item_id, actual.Id);
            Assert.AreEqual("test2", actual.Key);
            Assert.AreEqual(expected.ew_xml_value, actual.Value.ToText());
            Assert.AreEqual(expected.ew_uid_selection_id, actual.SelectionDefinitionId);
            Assert.AreEqual(expected.ew_dt_created.ToUtc(), actual.Created);
            Assert.AreEqual(expected.ew_nvc_created_by, actual.CreatedBy);
            Assert.AreEqual(expected.ew_dt_modified.ToUtc(), actual.Modified);
            Assert.AreEqual(expected.ew_nvc_modified_by, actual.ModifiedBy);
            CollectionAssert.AreEqual(expected.ew_t_timestamp, actual.Timestamp);
        }

        [TestMethod]
        public async Task Delete_Test()
        {
            var expected = CreateRawSelectionItem("test1");
            await this.TestDbContext.SaveChangesAsync();
            await this.TestDbContext.Entry(expected).ReloadAsync();

            await this.SelectionItemDefinitionDao.DeleteAsync(expected.ew_uid_selection_item_id, expected.ew_t_timestamp);

            var actual = await this.TestDbContext.ew_tbl_selection_items.CountAsync();
            Assert.AreEqual(0, actual);
        }

        [TestMethod]
        [ExpectedException(typeof(EWDataException))]
        public async Task CreateDuplicate_Test()
        {
            var text = new EWText();
            text.Values.Add(new EWTextValue("en", "v1"));
            text.Values.Add(new EWTextValue("zh-Hans", "v2"));
            var expected = new EWSelectionItemDefinition()
            {
                Key = "test",
                Value = text,
                SelectionDefinitionId = this.Selection.ew_uid_selection_id
            };

            await this.SelectionItemDefinitionDao.CreateAsync(expected);
            await this.SelectionItemDefinitionDao.CreateAsync(expected);
        }

        [TestMethod]
        public async Task CreateEquivalent_Test()
        {
            var selection1 = CreateRawSelection("test1");
            var selection2 = CreateRawSelection("test2");

            var text = new EWText();
            text.Values.Add(new EWTextValue("en", "v1"));
            text.Values.Add(new EWTextValue("zh-Hans", "v2"));

            await this.SelectionItemDefinitionDao.CreateAsync(new EWSelectionItemDefinition()
            {
                Key = "test",
                Value = text,
                SelectionDefinitionId = selection1.ew_uid_selection_id
            });
            await this.SelectionItemDefinitionDao.CreateAsync(new EWSelectionItemDefinition()
            {
                Key = "test",
                Value = text,
                SelectionDefinitionId = selection2.ew_uid_selection_id
            });

            var count = await this.TestDbContext.ew_tbl_selection_items.CountAsync(e => e.ew_vc_key == "test");
            Assert.AreEqual(2, count);
        }

        [TestInitialize]
        public override void TestInitialize()
        {
            base.TestInitialize();

            this.Selection = CreateRawSelection("test");
        }

        private ew_tbl_selections CreateRawSelection(string name)
        {
            var text = new EWText();
            text.Values.Add(new EWTextValue("en", "v1"));
            text.Values.Add(new EWTextValue("zh-Hans", "v2"));
            var result = new ew_tbl_selections()
            {
                ew_uid_selection_id = Guid.NewGuid(),
                ew_dt_created = DateTime.UtcNow,
                ew_nvc_created_by = "test",
                ew_dt_modified = DateTime.UtcNow,
                ew_nvc_modified_by = "test",
                ew_vc_internal_name = name,
                ew_xml_display_name = text.ToText()
            };
            this.TestDbContext.ew_tbl_selections.Add(result);
            this.TestDbContext.SaveChanges();

            return result;
        }

        private ew_tbl_selection_items CreateRawSelectionItem(string key)
        {
            var text = new EWText();
            text.Values.Add(new EWTextValue("en", "v1"));
            text.Values.Add(new EWTextValue("zh-Hans", "v2"));
            var item = new ew_tbl_selection_items()
            {
                ew_uid_selection_item_id = Guid.NewGuid(),
                ew_uid_selection_id = this.Selection.ew_uid_selection_id,
                ew_dt_created = DateTime.UtcNow,
                ew_nvc_created_by = "test",
                ew_dt_modified = DateTime.UtcNow,
                ew_nvc_modified_by = "test",
                ew_vc_key = key,
                ew_xml_value = text.ToText()
            };

            this.TestDbContext.ew_tbl_selection_items.Add(item);

            return item;
        }
    }
}
